package log

import (
	"dev.ixmxm.top/rms/utils/buffer"
	"runtime"
)

func getStack() string {
	buf := buffer.Get()
	defer buf.Free()
	var numFrames int
	counter := newProgramCounters(64)
	for {
		// Skip the call to runtime.Counters and takeStacktrace so that the
		// program counters start at the caller of takeStacktrace.
		numFrames = runtime.Callers(5, counter.pcs)
		if numFrames < len(counter.pcs) {
			break
		}
		// Don't put the too-short counter slice back into the pool; this lets
		// the pool adjust if we consistently take deep stacktraces.
		counter = newProgramCounters(len(counter.pcs) * 2)
	}

	i := 0
	frames := runtime.CallersFrames(counter.pcs[:numFrames])
	for frame, more := frames.Next(); more; frame, more = frames.Next() {
		if i != 0 {
			buf.AppendByte('\n')
		}
		i++
		buf.AppendString(frame.Function)
		buf.AppendByte('\n')
		buf.AppendByte('\t')
		buf.AppendString(frame.File)
		buf.AppendByte(':')
		buf.AppendInt(int64(frame.Line))
	}

	return buf.String()
}

type programCounters struct {
	pcs []uintptr
}

func newProgramCounters(size int) *programCounters {
	return &programCounters{make([]uintptr, size)}
}
